import { sleep } from '.'
import { TipModal } from './class/tip-modal'
import axios, { HttpStatusCode } from 'axios'
import { getAccessToken } from './cache/token.cache'
import { LOGIN_PAGE_URL } from '@/router/router.constant'

/** 根据配置决定是否开启请求接口时的顶部进度条 */
const NProgress = useNProgress({ show: __RUNTIME_CONFIG__.VITE_REQUEST_NPROGRESS }) // 顶部进度条

const request = axios.create({
  // baseURL 将自动加在 url 前面，除非 url 是一个绝对 URL
  baseURL: __RUNTIME_CONFIG__.VITE_BASE_API,
  // timeout 指定请求超时的毫秒数(0 表示无超时时间)，如果请求花费了超过 timeout 的时间，请求将被中断
  timeout: __RUNTIME_CONFIG__.VITE_REQUEST_TIMEOUT * 1000,
})

// 请求拦截器
request.interceptors.request.use(
  (config) => {
    NProgress.start() // 开启响应进度条
    const timestamp = Date.now()
    const accessToken = getAccessToken()
    config.params = config.params || {}

    // 给 get 请求加上时间戳参数，避免从缓存中拿数据
    if (config.method?.toUpperCase() === 'GET') Reflect.set(config.params, 'timestamp', timestamp)

    // 让每个请求携带自定义 token 请根据实际情况自行修改
    if (accessToken) Reflect.set(config.headers, 'Authorization', `Bearer ${accessToken}`)

    // 返回处理后的请求头
    return config
  },
  (error) => {
    NProgress.done()
    return Promise.reject(error)
  },
)

// 响应拦截器
request.interceptors.response.use(
  async (response) => {
    NProgress.done()
    const { config, data, headers } = response
    const contentType = (Reflect.get(headers, 'content-type') || '') as string
    const isBinaryType = ['arraybuffer', 'blob'].includes(response.request.responseType)
    const isJsonContent = contentType.includes('application/json')

    // 未设置状态码则默认成功状态
    let code = data.code || HttpStatusCode.Ok
    // 获取错误信息
    let message = data.message || `系统未知错误，请反馈给管理员`
    // 二进制数据则直接返回
    if (isBinaryType && !isJsonContent) return response
    // 二进制数据 但实际数据为 JSON 类型时
    if (isBinaryType && isJsonContent) {
      const jsonStr = new TextDecoder().decode(data) // 将 arraybuffer 转换为 JSON 字符串
      const error = JSON.parse(jsonStr) // 解析为 JSON 对象并抛出错误，供上层捕获
      code = error.code
      message = error.message
    }
    // 非二进制且状态码为成功状态码 直接返回具体数据 {code, message, result, timestamp}
    if (code === HttpStatusCode.Ok && !isBinaryType) {
      return data.data
    }
    // 登录过期且非登录接口
    if (code === HttpStatusCode.Unauthorized) {
      TipModal.msgError(message ?? `会话已过期，即将重新登录`)
      await useUserStore().logout()
      await sleep(640)
      TipModal.msgWarning(`即将跳转登录页，请稍后`)
      await sleep(640)
      return window.location.reload()
    }
    // 能到这里的基本都是异常返回了
    TipModal.msgError(message, { duration: 5 * 1000 }) // 此处可统一处理错误的提示消息
    return Promise.reject(new Error(message))
  },
  (error: any) => {
    NProgress.done()
    // 参考：https://gitee.com/y_project/RuoYi-Vue/blob/master/ruoyi-ui/src/utils/request.js
    let { message } = error
    if (message == 'Network Error') {
      message = '后端接口连接异常'
    } else if (message.includes('timeout')) {
      message = '系统接口请求超时'
    } else if (message.includes('Request failed with status code')) {
      message = `系统接口 ${message.substr(message.length - 3)} 异常`
    }
    // 如果后端返回错误提示信息，则采用该信息提示
    if (error.response && error.response.data && error.response.data.message) {
      message = error.response.data.message
    }
    TipModal.msgError(message, { duration: 5 * 1000 })
    return Promise.reject(error)
  },
)

export default request
